﻿#include <iostream>
#include <WINSOCK2.h>
#include <time.h>
#include <string.h>
#include <fstream>
#pragma comment(lib, "ws2_32.lib")

using namespace std;

SOCKADDR_IN server_addr;
SOCKET server;
int len;
const int port = 1234;
const int timeout = CLOCKS_PER_SEC;
const int bufsize = 1024;//传输缓冲区最大长度
const unsigned char SYN = 0x1; // 10
const unsigned char ACK = 0x2; // 01 
const unsigned char SYN_ACK = 0x3; //11 
const unsigned char FIN = 0x4; //FIN = 1,ACK = 0
const unsigned char FIN_ACK = 0x5; //
const unsigned char OVER = 0x7;//结束

struct HEADER
{
    uint16_t sum = 0; // 校验和
    uint16_t len = 0; //数据长度
    unsigned char flag = 0; //标记位_ _ _ _ _ FIN ACK SYN 
    unsigned char seq = 0; //序列号，0~255，超出取模
};

void open_Socket()
{
    WSADATA wsadata;
    WSAStartup(MAKEWORD(2, 2), &wsadata);

    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);
    server_addr.sin_addr.s_addr = htonl(2130706433);//INADDR_ANY

    server = socket(AF_INET, SOCK_DGRAM, 0);
}

uint16_t cksum(uint16_t* buffer, int count) {
    /*if (count == 0)
        return ~(0);*/
    uint16_t* buf = (uint16_t*)malloc(count);
    memcpy(buf, buffer, count);
    count = (count + 1) / 2;
    register uint32_t sum = 0;
    while (count--) {
        sum += *buf++;
        if (sum & 0XFFFF0000) {
            sum &= 0XFFFF;
            sum++;
        }
    }
    return ~(sum & 0XFFFF);
}

bool shakehand()//三次握手建立连接
{
    HEADER head;
    char* buf = new char[sizeof(head)];
    uint16_t sum;

    //第一次握手
    head.sum = 0;
    head.flag = SYN;
    head.sum = cksum((uint16_t*)&head, sizeof(head));
    memcpy(buf, &head, sizeof(head));
    sendto(server, buf, sizeof(head), 0, (sockaddr*)&server_addr, len);
    //return false;
    clock_t start = clock(); //发送第一次握手请求的时间

    u_long argp = 1;
    ioctlsocket(server, FIONBIO, &argp);//非阻塞

    //第二次握手
    while (recvfrom(server, buf, sizeof(head), 0, (sockaddr*)&server_addr, &len) <= 0) {
        if (clock() - start > timeout) { //超时重传
            head.sum = 0;
            head.flag = SYN;
            head.sum = cksum((uint16_t*)&head, sizeof(head));
            memcpy(buf, &head, sizeof(head));
            sendto(server, buf, sizeof(head), 0, (sockaddr*)&server_addr, len);
            start = clock();
            cout << "第一次握手超时重传ing" << endl;
        }
    }
    memcpy(&head, buf, sizeof(head));
    if (head.flag == ACK && cksum((uint16_t*)&head, sizeof(head) == 0))
        cout << "第二次握手成功\n";
    else {
        cout << "连接失败\n";
        return false;
    }
    //第三次握手
    head.sum = 0;
    head.flag = SYN_ACK;
    head.sum = cksum((uint16_t*)&head, sizeof(head));
    sendto(server, (char*)&head, sizeof(head), 0, (sockaddr*)&server_addr, len);
    cout << "服务器连接成功！\n输入要发送的文件：";
    return true;
}


void send_package(char* message, int mlen, int& seq)
{
    HEADER head;
    char* buffer = new char[bufsize + sizeof(head)];
    head.len = mlen;
    head.seq = unsigned char(seq);
    memcpy(buffer, &head, sizeof(head));
    memcpy(buffer + sizeof(head), message, sizeof(head) + mlen);
    head.sum = cksum((uint16_t*)buffer, sizeof(head) + mlen);
    memcpy(buffer, &head, sizeof(head));
    sendto(server, buffer, mlen + sizeof(head), 0, (sockaddr*)&server_addr, len);
    cout << "发送数据: " << mlen << " bytes, FLAG:" << int(head.flag) << " SEQ:" << int(head.seq) << " SUM:" << int(head.sum) << endl;
    clock_t start = clock();
    //接收ACK
    while (1) {
        u_long argp = 1;
        ioctlsocket(server, FIONBIO, &argp);
        while (recvfrom(server, buffer, bufsize, 0, (sockaddr*)&server_addr, &len) <= 0) {
            if (clock() - start > timeout) {//超时重传
                head.len = mlen;
                head.seq = u_char(seq);
                head.flag = u_char(0X0);
                memcpy(buffer, &head, sizeof(head));
                memcpy(buffer + sizeof(head), message, sizeof(head) + mlen);
                head.sum = cksum((uint16_t*)buffer, sizeof(head) + mlen);
                memcpy(buffer, &head, sizeof(head));
                sendto(server, buffer, mlen + sizeof(head), 0, (sockaddr*)&server_addr, len);//发送
                cout << "超时重传: " << mlen << " bytes, FlAG:" << int(head.flag) << " SEQ:" << int(head.seq) << endl;
                clock_t start = clock();
            }
        }
        memcpy(&head, buffer, sizeof(head));
        uint16_t check = cksum((uint16_t*)&head, sizeof(head));
        if (head.seq == uint16_t(seq) && head.flag == ACK) {
            cout << "对方成功接收文件 FlAG:" << int(head.flag) << " SEQ:" << int(head.seq) << endl;
            break;
        }
        else
            continue;

    }
    u_long argp = 0;
    ioctlsocket(server, FIONBIO, &argp);
}

void _send(char* message, int mlen)
{
    int pnum = mlen / bufsize + ( (mlen % bufsize) ? 1 : 0);//包数
    int seq = 0;
    for (int i = 0; i < pnum; i++) {
        send_package(message + i * bufsize, i == pnum - 1 ? mlen - (pnum - 1) * bufsize : bufsize, seq);
        seq++;
        if (seq > 255)
            seq -= 256;
    }
    //发送OVER
    HEADER head;
    char* Buffer = new char[sizeof(head)];
    head.flag = OVER;
    head.sum = 0;
    head.sum = cksum((uint16_t*)&head, sizeof(head));
    memcpy(Buffer, &head, sizeof(head));
    sendto(server, Buffer, sizeof(head), 0, (sockaddr*)&server_addr, len);
    cout << "发送完成\n";
    clock_t start = clock();
    while (1) {
        u_long argp = 1;
        ioctlsocket(server, FIONBIO, &argp);
        while (recvfrom(server, Buffer, bufsize, 0, (sockaddr*)&server_addr, &len) <= 0) {
            if (clock() - start > timeout) {
                char* Buffer = new char[sizeof(head)];
                head.flag = OVER;
                head.sum = 0;
                uint16_t temp = cksum((uint16_t*)&head, sizeof(head));
                head.sum = temp;
                memcpy(Buffer, &head, sizeof(head));
                sendto(server, Buffer, sizeof(head), 0, (sockaddr*)&server_addr, len);
                cout << "超时重传\n";
                start = clock();
            }
        }
        memcpy(&head, Buffer, sizeof(head));//缓冲区接收到信息，读取
        uint16_t check = cksum((uint16_t*)&head, sizeof(head));
        if (head.flag == OVER) {
            cout << "对方成功接收文件\n";
            break;
        }
        else
            continue;
    }
    u_long argp = 0;
    ioctlsocket(server, FIONBIO, &argp);//改回阻塞模式
}



bool wavehand()
{
    HEADER header;
    char* Buffer = new char[sizeof(header)];

    uint16_t sum;

    //第一次握手
    header.sum = 0;
    header.flag = FIN;
    uint16_t temp = cksum((uint16_t*)&header, sizeof(header));
    header.sum = temp;
    memcpy(Buffer, &header, sizeof(header));
    sendto(server, Buffer, sizeof(header), 0, (sockaddr*)&server_addr, len);
    clock_t start = clock();

    u_long argp = 1;
    ioctlsocket(server, FIONBIO, &argp);
    //第二次挥手
    while (recvfrom(server, Buffer, sizeof(header), 0, (sockaddr*)&server_addr, &len) <= 0) {
        if (clock() - start > timeout) {//超时重传
            header.sum = 0;
            header.flag = FIN;
            header.sum = cksum((uint16_t*)&header, sizeof(header));
            memcpy(Buffer, &header, sizeof(header));
            sendto(server, Buffer, sizeof(header), 0, (sockaddr*)&server_addr, len);
            start = clock();
            cout << "第一次挥手超时重传ing\n";
        }
    }

    memcpy(&header, Buffer, sizeof(header));
    if (header.flag == ACK && cksum((uint16_t*)&header, sizeof(header) == 0))
        cout << "第二次挥手成功\n";
    else
    {
        cout << "连接失败\n";
        return false;
    }
    //第三次挥手
    header.sum = 0;
    header.flag = FIN_ACK;
    header.sum = cksum((uint16_t*)&header, sizeof(header));//计算校验和
    sendto(server, (char*)&header, sizeof(header), 0, (sockaddr*)&server_addr, len);
    start = clock();
    //第四次挥手
    while (recvfrom(server, Buffer, sizeof(header), 0, (sockaddr*)&server_addr, &len) <= 0)
    {
        if (clock() - start > timeout)//超时重传
        {
            header.sum = 0;
            header.flag = FIN;
            header.sum = cksum((uint16_t*)&header, sizeof(header));
            memcpy(Buffer, &header, sizeof(header));
            sendto(server, Buffer, sizeof(header), 0, (sockaddr*)&server_addr, len);
            start = clock();
            cout << "第四次握手超时重传ing\n";
        }
    }
    cout << "四次挥手结束，连接断开！\n";
    return true;
}


int main()
{
    open_Socket();
    len = sizeof(server_addr);
    string filename;
    char* buf = new char[10000000];
    int index = 0;

    if (!shakehand())
        return 0;
    cin >> filename;
    ifstream ifile(filename.c_str(), ifstream::binary);//
    unsigned char byte = ifile.get();
    while (!ifile.eof())
    {
        buf[index++] = byte;
        byte = ifile.get();
    }
    _send((char*)(filename.c_str()), filename.length());
    clock_t start = clock();
    _send(buf, index);
    clock_t end = clock();
    float trantime = (end - start) / CLOCKS_PER_SEC;
    cout << "传输时间:" << trantime << "s\n";
    cout << "吞吐率:" << ((float)index) / trantime << "byte/s\n";

    wavehand();
    ifile.close();
    system("pause");
    return 0;
}
